﻿using Engine.FileFormats3D.WR2TerrainLoader.Misc;
using Engine.Graphics;
using Engine.Physic;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using WorldRacing2.Configuration.GroundConfig;

namespace WorldRacing2.Configuration.Material
{
    internal partial class TextureSetupWindow : UserControl
    {
        #region Private Fields

        private WorldRacing2ConfigurationData configurationData;
        private bool duringControlUpdate = false;
        private MaterialManager materialManager;

        #endregion Private Fields

        #region Public Constructors

        public TextureSetupWindow(WorldRacing2ConfigurationData configurationData)
        {
            InitializeComponent();
            this.configurationData = configurationData;

            this.groundControl1.groundListChange += new GroundConfig.GroundControl.OnGroundListChange(OnGroundListChange);

            LoadTextureToMaterialFile(this.configurationData.TextureToMaterialFile);
        }

        #endregion Public Constructors

        #region Public Methods

        public List<Ground> GetGrounds()
        {
            return this.groundControl1.GetGrounds();
        }

        public void SetMaterialManager(MaterialManager materialManager)
        {
            //this.groundControl1.LoadDefaultGrounds("default.grounds");
            this.materialManager = materialManager;
            MaterialManagerChanged(this.materialManager, null);
        }

        public void ToFile(string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);
            this.configurationData.TextureToMaterialFile.ToStream(bw, this.groundControl1.groundsFile);
            bw.Close();
            fs.Close();
        }

        #endregion Public Methods

        #region Private Methods

        private void checkBox_HasGras_CheckedChanged(object sender, EventArgs e)
        {
            if (!this.duringControlUpdate)
            {
                ListBox master = this.listBox_TexturesLeft;

                List<TexturePropertie> selectedTextureProperties = new List<TexturePropertie>();

                for (int i = 0; i < master.SelectedIndices.Count; i++)
                {
                    TexturePropertie texturePropertie = (TexturePropertie)master.Items[master.SelectedIndices[i]];
                    texturePropertie.HasGras = this.checkBox_HasGras.Checked;
                    texturePropertie.Enlite = this.checkBox_Enlite.Checked;
                }
            }
        }

        private void CreateDefaultFile(string filename)
        {
            FileStream fs = File.Create(filename);
            fs.Close();

            this.configurationData.TextureToMaterialFile.CreateStandardFile(filename, this.materialManager);

            UpdateListBox(this.domainUpDown_GroundsLeft, EventArgs.Empty);
            UpdateListBox(this.domainUpDown_GroundsRight, EventArgs.Empty);

            ToFile(filename);
        }

        private void listBox_TexturesLeft_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            PutLeftElementsToRightListbox(null, null);
        }

        private void listBox_TexturesLeft_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.duringControlUpdate = true;
            this.pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
            if (this.listBox_TexturesLeft.SelectedIndices.Count == 1)
            {
                int index = this.materialManager.TextureNames.IndexOf(this.listBox_TexturesLeft.SelectedItem.ToString());
                TexturePropertie texturePropertie = (TexturePropertie)this.listBox_TexturesLeft.SelectedItem;
                if (index > -1)
                {
                    try
                    {
                        this.pictureBox1.Image = Ptx2bmpConverter.Ptx2bmp.FromFile(this.materialManager.TexturePaths[index]);
                    }
                    catch (Exception ex)
                    {
                        this.pictureBox1.Image = this.pictureBox1.ErrorImage;
                        Console.WriteLine(ex.Message);
                    }
                }
                this.checkBox_Enlite.Checked = texturePropertie.Enlite;
                this.checkBox_HasGras.Checked = texturePropertie.HasGras;
            }
            this.duringControlUpdate = false;
        }

        private void LoadTextureToMaterialFile(TextureToMaterialFile textureToMaterialFile)
        {
            this.configurationData.TextureToMaterialFile = textureToMaterialFile;
            // Set grounds in ground control.
            this.groundControl1.SetGroundsFile(this.configurationData.GroundsFile);

            // Order by values.
            // Use LINQ to specify sorting by value.
            var items = from k in this.configurationData.TextureToMaterialFile.TextureProperties.Keys
                        orderby this.configurationData.TextureToMaterialFile.TextureProperties[k] ascending
                        select k;
            if (this.materialManager != null)
                UpdateListBox(null, null);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender">Material Manager</param>
        /// <param name="e"></param>
        private void MaterialManagerChanged(object sender, EventArgs e)
        {
            Debug.WriteLine("new MaterialManager for TextureSetupWindow");
            this.materialManager = (MaterialManager)sender;

            this.configurationData.TextureToMaterialFile.SetMaterialManagre(this.materialManager);

            UpdateListBox(null, null);
        }

        private void OnGroundListChange(object sender, EventArgs e)
        {
            List<Ground> grounds = (List<Ground>)sender;

            this.domainUpDown_GroundsLeft.Items.Clear();
            this.domainUpDown_GroundsRight.Items.Clear();

            this.domainUpDown_GroundsLeft.Items.AddRange(grounds);
            this.domainUpDown_GroundsRight.Items.AddRange(grounds);

            this.domainUpDown_GroundsLeft.SelectedIndex = 0;
            this.domainUpDown_GroundsRight.SelectedIndex = 0;
        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "textureSetup.bin (*.bin)|*.bin";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                //FromFile("textureSetup.bin");
                GroundsFile groundsFile;
                LoadTextureToMaterialFile(TextureToMaterialFile.FromFile(ofd.FileName, out groundsFile));

                this.configurationData.GroundsFile = groundsFile;
            }
        }

        private void PutLeftElementsToRightListbox(object sender, EventArgs e)
        {
            ListBox master = this.listBox_TexturesLeft;
            ListBox slave = this.listBoxTexturesRight;
            List<TexturePropertie> selectedTextureProperties = new List<TexturePropertie>();
            int lastIndex = master.Items.Count - 1, i;

            for (i = 0; i < master.SelectedIndices.Count; i++)
            {
                lastIndex = Math.Min(lastIndex, master.SelectedIndices[i]);
                TexturePropertie texturePropertie = (TexturePropertie)master.Items[master.SelectedIndices[i]];
                int test = master.PreferredHeight;
                texturePropertie.GroundName = this.domainUpDown_GroundsRight.SelectedItem.ToString();
                master.Items.RemoveAt(master.SelectedIndices[i]);
                i--;
            }
            UpdateListbox(this.domainUpDown_GroundsRight, slave);
        }

        private void PutRightElementsToLeftListbox(object sender, EventArgs e)
        {
            ListBox master = this.listBoxTexturesRight;
            ListBox slave = this.listBox_TexturesLeft;
            List<TexturePropertie> selectedTextureProperties = new List<TexturePropertie>();
            int lastIndex = master.Items.Count - 1, i;

            for (i = 0; i < master.SelectedIndices.Count; i++)
            {
                lastIndex = Math.Min(lastIndex, master.SelectedIndices[i]);
                TexturePropertie texturePropertie = (TexturePropertie)master.Items[master.SelectedIndices[i]];
                texturePropertie.GroundName = this.domainUpDown_GroundsLeft.SelectedItem.ToString();
                master.Items.RemoveAt(master.SelectedIndices[i]);
                i--;
            }
            UpdateListbox(this.domainUpDown_GroundsLeft, slave);
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "textureSetup.bin (*.bin)|textureSetup.bin";
            sfd.FileName = Application.StartupPath + "\\textureSetup.bin";
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                //ToFile("textureSetup.bin");
                ToFile(sfd.FileName);
            }
        }

        private void UpdateListbox(DomainUpDown domainUpDown, ListBox listbox)
        {
            List<Ground> grounds = this.groundControl1.GetGrounds();
            List<string> groundNames = new List<string>();
            List<string> textureNamesLeft = new List<string>();
            listbox.BeginUpdate();

            for (int i = 0; i < grounds.Count; i++)
            {
                groundNames.Add(grounds[i].ToString());
            }

            // Check if the assigned groundname exists.
            for (int i = 0; i < this.configurationData.TextureToMaterialFile.TextureProperties.Count; i++)
            {
                if (!groundNames.Contains(this.configurationData.TextureToMaterialFile.TextureProperties.ElementAt(i).Value.GroundName))
                {
                    string key = this.configurationData.TextureToMaterialFile.TextureProperties.ElementAt(i).Key;
                    TexturePropertie texturePropertie = this.configurationData.TextureToMaterialFile.TextureProperties.ElementAt(i).Value;
                    texturePropertie.GroundName = GroundControl.DEFAULT_GROUND_NAME;
                    this.configurationData.TextureToMaterialFile.TextureProperties.Remove(key);
                    this.configurationData.TextureToMaterialFile.TextureProperties.Add(key, texturePropertie);
                }
            }

            listbox.Items.Clear();

            if (domainUpDown.SelectedIndex > -1)
            {
                string currentSelectedGroundLeft = domainUpDown.SelectedItem.ToString();

                for (int i = 0; i < this.configurationData.TextureToMaterialFile.TextureProperties.Count; i++)
                {
                    if (this.configurationData.TextureToMaterialFile.TextureProperties.ElementAt(i).Value.GroundName == currentSelectedGroundLeft)
                        listbox.Items.Add(this.configurationData.TextureToMaterialFile.TextureProperties.ElementAt(i).Value);
                }
            }
            listbox.EndUpdate();
        }

        private void UpdateListBox(object sender, EventArgs e)
        {
            UpdateListbox(this.domainUpDown_GroundsLeft, this.listBox_TexturesLeft);
            UpdateListbox(this.domainUpDown_GroundsRight, this.listBoxTexturesRight);
        }

        #endregion Private Methods
    }
}